# -*- coding: utf-8 -*-
# vim: set filetype=python: expandtab tabstop=4 shiftwidth=4 autoindent smartindent nu:
# kate: space-indent on; tab-width 4; indent-width 4; indent-mode python; backspace-indents; encoding utf-8; line-numbers on; remove-trailing-space on;
#   Copyright 2010 Thomas Olsen <tanghus@gmail.com>
#
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU Library General Public License as
#   published by the Free Software Foundation; either version 2 or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#
#   GNU General Public License for more details
#
#
#   You should have received a copy of the GNU Library General Public
#   License along with this program; if not, write to the
#   Free Software Foundation, Inc.,
#
#   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
#
from PyQt4 import QtCore
from PyQt4.QtCore import * # Qt, QVariant, QSize, SIGNAL
from PyQt4.QtGui import *
from PyKDE4.kio import *
from PyKDE4.kdecore import KTempDir, KStandardDirs, i18n, KUrl
from PyKDE4.kdeui import KIcon
from PyKDE4.plasma import Plasma
from socialnetworks import socialnetworks
from webservices import webservices
from urllib import quote, urlencode
import datetime, os

class IconGetter(QObject):
    map_fetched = QtCore.pyqtSignal()
    icon_fetched = QtCore.pyqtSignal()
    def __init__(self, icondict, address=None):
        QObject.__init__(self)
        self.icondict = icondict
        self.address = address
        self.tmpdir = KTempDir(KStandardDirs.locateLocal("tmp", "lastfmevent"))
        if not self.tmpdir.exists():
            print "Error creating tmp dir: " + str(self.tmpdir.name())
        #else:
            #print "Created tmp dir: " + str(self.tmpdir.name())
        self.fetch_icons()
        self.has_map = self.fetch_map()

    def fetch_map(self):
        #baseurl = "http://maps.google.com/maps/api/staticmap?center=Enghavevej+40,Copenhagen,Denmark&zoom=13&size=256x256&maptype=roadmap&markers=color:blue|label:E|55.668091,12.544307&sensor=false"
        baseurl = "http://maps.google.com/maps/api/staticmap?center=%s&zoom=14&size=256x256&maptype=roadmap&markers=color:blue|label:E|%s&sensor=false"
        if self.address and len(self.address) == 6:
            for part in self.address:
                if len(part) == 0:
                    return False

            address = "%s,%s %s,%s" % (self.address[0], self.address[1], self.address[2], self.address[3])
            address = quote(address.encode("utf-8"))
            latlong = "%s,%s" % (self.address[4], self.address[5])
            url = baseurl % (address, latlong)
            #print url

            job = KIO.file_copy(KUrl(url), KUrl("%s%s.%s" % (str(self.tmpdir.name()), "map", "png")), -1, KIO.HideProgressInfo)
            if job:
                #print "Copied " + str(url) + " to " + self.tmpdir.name()
                job.result.connect(self.map_job_done)
            else:
                print "Couldn't copy " + str(url) + " to " + self.tmpdir.name()
                return False
        else:
            return False

    def fetch_icons(self):
        if len(self.icondict["large"]) > 0:
            ext = self.icondict["large"][-3:] # The original extension
            job = KIO.file_copy(KUrl(self.icondict["large"]), KUrl("%s%s.%s" % (str(self.tmpdir.name()), "large", ext)), -1, KIO.HideProgressInfo)
            if job:
                #print "Copied " + str(self.icondict["large"]) + " to " + self.tmpdir.name()
                job.result.connect(self.icon_job_done)
            else:
                print "Couldn't copy " + str(self.icondict[size]) + " to " + self.tmpdir.name()

        #for size in self.icondict.keys():
            #if len(self.icondict[size]) > 0:
                #if KIO.file_copy(KUrl(self.icondict[size]), KUrl("%s%s.%s" % (str(self.tmpdir.name()), size, "jpg")), -1, KIO.HideProgressInfo):
                    #print "Copied " + str(self.icondict[size]) + " to " + self.tmpdir.name()
                #else:
                    #print "Couldn't copy " + str(self.icondict[size]) + " to " + self.tmpdir.name()

    def get_icon_path(self, size):
        if self.icondict.has_key(size) or size == "map":
            if size != "map":
                if len(self.icondict[size]) == 0:
                    return None
            ext = size == "map" and "png" or self.icondict[size][-3:] # The original extension
            path = "%s%s.%s" % (str(self.tmpdir.name()), size, ext)
            # Check if icon exists and is readable.
            #if not os.access(path, os.R_OK):
                #return None
        else:
            return None
        #print "Returning path: %s" % path
        return path

    @QtCore.pyqtSlot(name="map_job_done")
    def map_job_done(self, job=None):
        #print "Map fetched"
        self.map_fetched.emit()

    @QtCore.pyqtSlot(name="icon_job_done")
    def icon_job_done(self, job=None):
        #print "Icon fetched"
        self.icon_fetched.emit()

class LastFMEvent(Plasma.Frame):
    open_url = QtCore.pyqtSignal(QString)

    def __init__(self, eventelem, applet):
        QGraphicsWidget.__init__(self)
        self.applet = applet
        self.data = {}

        self.lb_image_small = Plasma.IconWidget(self)
        self.lb_image_small.setIcon("view-calendar-upcoming-events")
        self.lb_image_small.clicked.connect(self.open_event)
        self.lb_image_small.setMaximumIconSize(self.lb_image_small.sizeFromIconSize(64))
        self.lb_image_small.setPreferredIconSize(QSizeF(64.0, 64.0))

        #self.bt_event = Plasma.ToolButton(self)
        #self.bt_event.nativeWidget().setMaximumSize(QSize(24, 24))
        #self.bt_event.nativeWidget().setIcon(KIcon("view-calendar-upcoming-events"))
        #self.bt_event.nativeWidget().setToolTip(i18n("View event on Last.fm"))
        #self.bt_event.clicked.connect(self.open_event)

        self.bt_map = Plasma.ToolButton(self)
        self.bt_map.nativeWidget().setMaximumSize(QSize(26, 26))
        self.bt_map.nativeWidget().setIcon(KIcon("zoom-in"))
        self.bt_map.nativeWidget().setToolTip(i18n("View on Google Maps"))
        self.bt_map.clicked.connect(self.open_map)

        self.bt_venue = Plasma.ToolButton(self)
        self.bt_venue.nativeWidget().setMaximumSize(QSize(26, 26))
        self.bt_venue.nativeWidget().setIcon(KIcon("system-users"))
        self.bt_venue.nativeWidget().setToolTip(i18n("View venue on Last.fm"))
        self.bt_venue.clicked.connect(self.open_venue)

        self.bt_mail = Plasma.ToolButton(self)
        self.bt_mail.nativeWidget().setMaximumSize(QSize(26, 26))
        self.bt_mail.nativeWidget().setIcon(KIcon("internet-mail"))
        self.bt_mail.nativeWidget().setToolTip(i18n("Send event link by mail"))
        self.bt_mail.clicked.connect(self.open_mailer)

        self.bt_share = Plasma.ToolButton(self)
        self.bt_share.nativeWidget().setMaximumSize(QSize(26, 26))
        self.bt_share.nativeWidget().setIcon(KIcon(self.applet.package().filePath("images", "%s.png" % "openshareicon")))
        self.bt_share.nativeWidget().setToolTip(i18n("Click to share this event."))
        self.bt_share.clicked.connect(self.bt_share_clicked)
        #self.bt_share.nativeWidget().setPopupMode(QToolButton.InstantPopup)

        # NOTE: Maybe the menu can be shared between all events?
        # On second thought the all the events would be connected to the same menu :-/
        self.share_menu = QMenu()
        self.share_menu.triggered.connect(self.share_event)

        for s in applet.socialnetworks:
            path = self.applet.package().filePath("images", "%s.png" % s)
            #print s + ": " + path
            act = QAction(QIcon(path), socialnetworks[s]["name"], self)
            act.setData(QVariant(s))
            self.share_menu.addAction(act) # NOTE: Can this maybe hold a QVariant?

        #self.bt_share.nativeWidget().setMenu(self.share_menu)

        self.lb_headline = Plasma.Label(self)
        #self.lb_headline.linkActivated.connect(self.open_event)
        self.lb_headline.nativeWidget().setTextInteractionFlags(Qt.LinksAccessibleByMouse|Qt.LinksAccessibleByKeyboard)
        self.lb_headline.nativeWidget().setOpenExternalLinks(True)
        self.lb_headline.nativeWidget().setWordWrap(False)
        self.lb_startdate = Plasma.Label(self)
        self.lb_desc = Plasma.TextBrowser(self)
        self.lb_desc.nativeWidget().setTextInteractionFlags(Qt.LinksAccessibleByMouse|Qt.LinksAccessibleByKeyboard)
        self.lb_desc.nativeWidget().setMaximumHeight(160)
        self.lb_desc.hide()
        #self.lb_desc.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        #self.lb_desc.nativeWidget().setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        #self.lb_desc.nativeWidget().setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        #self.lb_desc.nativeWidget().setCursor(Qt.ArrowCursor)
        self.lb_address = Plasma.Label(self)
        self.lb_address.nativeWidget().setTextInteractionFlags(Qt.LinksAccessibleByMouse|Qt.LinksAccessibleByKeyboard)
        self.lb_address.nativeWidget().setOpenExternalLinks(True)
        #self.lb_address.nativeWidget().setWordWrap(False)
        self.lb_tags = Plasma.Label(self)
        self.lb_attendance = Plasma.Label(self)
        self.geolocation = []
        self.website = ""
        self.lasturl = ""
        self.ticketsurl = ""
        self.tags = []


        self.layout = QGraphicsLinearLayout(self)
        pic_layout = QGraphicsLinearLayout(Qt.Vertical)
        pic_layout.addItem(self.lb_image_small)
        pic_layout.addStretch()
        btn_layout = QGraphicsGridLayout()
        btn_layout.addItem(self.bt_venue, 0, 0)
        btn_layout.addItem(self.bt_map, 0, 1)
        btn_layout.addItem(self.bt_mail, 1, 0)
        btn_layout.addItem(self.bt_share, 1, 1)
        pic_layout.addItem(btn_layout)
        txt_layout = QGraphicsLinearLayout(Qt.Vertical)
        txt_layout.addItem(self.lb_headline)
        txt_layout.addItem(self.lb_startdate)
        txt_layout.addItem(self.lb_address)
        txt_layout.addStretch()
        txt_layout.addItem(self.lb_tags)
        txt_layout.addStretch()
        self.layout.addItem(pic_layout)
        self.layout.addItem(txt_layout)
        self.layout.setStretchFactor(pic_layout, 1)
        self.layout.setStretchFactor(txt_layout, 3)

        self.setData(self.getEventData(eventelem))
        self.layout.invalidate()
        self.layout.activate()

    def getId(self):
        try:
            return int(self.data["id"])
        except:
            return -1

    @staticmethod
    def getGetIdFromDom(obj, eventelem):
        elem = eventelem.getElementsByTagName("id")
        rc = []
        for node in elem:
            #print "Type: %i" % node.nodeType
            try:
                if node.nodeType == node.TEXT_NODE or node.nodeType == node.CDATA_SECTION_NODE:
                    rc.append(node.data)
            except AttributeError:
                return elem
        return ''.join(rc)

    def getTitle(self):
        try:
            return self.data["title"]
        except:
            return ""

    # This should later be used be the data engine
    def setData(self, data):
        self.icongetter = IconGetter(self.data["image"]
                                    , (self.data["street"], self.data["postalcode"], self.data["city"]
                                    , self.data["country"], self.data["geo:lat"], self.data["geo:long"]))
        self.icongetter.map_fetched.connect(self.set_map)
        self.icongetter.map_fetched.connect(self.set_icon)
        self.setId(self.data["id"])
        self.setHeadline(self.data["title"])
        self.setStartDate(self.data["startDate"])
        self.setDesc(self.data["description"])
        self.setAddress(self.data["street"], self.data["postalcode"], self.data["city"], self.data["country"])
        #self.setGeoLocation(self.data.geolocation)
        self.setWebsite(self.data["website"])
        self.setLastUrl(self.data["url"])
        #self.setTicketsUrl(data.ticketsurl)
        self.setTags(self.data["tags"])
        #self.setAttendance(data.attendance)

    def getEventData(self, eventelem):
        #print "getEventData: " + str(eventelem)
        tags = ("id", "image", "title", "description", "startDate", "tag", "website", "street", "postalcode", "city", "country", "url", "attendance", "geo:lat", "geo:long")
        for tag in tags:
            if tag == "url":
                for elem in eventelem.getElementsByTagName(tag):
                    if elem.parentNode.tagName == "event":
                        self.data[tag] = self.getText(elem.childNodes)
                        #print "Got parent event for " + tag
                    elif elem.parentNode.tagName == "venue":
                        if not self.data.has_key("venue"):
                            self.data["venue"] = {}
                        self.data["venue"][tag] = self.getText(elem.childNodes)
            else:
                elem = eventelem.getElementsByTagName(tag)[0]
            self.data[tag] = self.getText(elem.childNodes)
            #print str(elem) + " " + tag + ": " + self.data[tag]

        mtags = {"tags":"tag"}
        for tag in mtags.keys():
            self.getElements(eventelem, mtags[tag], tag)

        atags = ["image"]
        for tag in atags:
            self.getAttributes(eventelem, tag)

        #print "getEventData end: " + str(self.data)
        return self.data

    def getElements(self, eventelem, node, tagname):
        #print "getElements: " + str(eventelem) + " " + node + " " + tagname
        self.data[tagname] = []
        try:
            elems = eventelem.getElementsByTagName(tagname)[0]
        except IndexError:
            return
        #print elems
        for elem in elems.childNodes:
            if elem.nodeType != elem.TEXT_NODE:
                #print "elem: " + str(elem) # + " : " + elem.data
                #print self.getText(elem.childNodes)
                self.data[tagname].append(self.getText(elem.childNodes))

    def getAttributes(self, eventelem, tagname):
        #print "getAttributes: " + tagname
        self.data[tagname] = {}
        for elem in eventelem.getElementsByTagName(tagname):
            if elem.parentNode.tagName == "event":
                #print elems
                while elem.nextSibling != None:
                    #print "Attribute: " + str(elems)
                    if elem.attributes:
                        #print elems.getAttribute("size")
                        #print self.getText(elems.childNodes)
                        self.data[tagname][elem.getAttribute("size")] = self.getText(elem.childNodes)
                    elem = elem.nextSibling

    def getText(self, elem):
        #print "getText"
        #print "elem: " + str(elem)
        rc = []
        if elem:
            for node in elem:
                #print "Type: %i" % node.nodeType
                try:
                    if node.nodeType == node.TEXT_NODE or node.nodeType == node.CDATA_SECTION_NODE:
                        rc.append(node.data)
                except AttributeError:
                    return elem
            return ''.join(rc)
        else:
            return ""

    def setId(self, id):
        self.id = id

    @QtCore.pyqtSlot(name="set_icon")
    def set_icon(self):
        #print "set_icon for '%s'" % self.data["title"]
        icon = self.icongetter.get_icon_path("large")
        if not icon:
            print "Couldn't get icon for '%s'. Using standard." % self.data["title"]
            icon = KIcon("view-calendar-upcoming-events")
        else:
            icon = KIcon(icon)
            if icon.isNull():
                icon = KIcon("view-calendar-upcoming-events")
        self.lb_image_small.setIcon(icon)
        if icon.isNull():
            print "ERROR: Couldn't load: " + icon
        # when the following is used the icon isn't shown ..?
        #self.lb_image_small.setMinimumSize(self.lb_image_small.sizeFromIconSize(64))

        # Setup tool tip
        self.tooltipdata = Plasma.ToolTipContent()
        self.tooltipdata.setAutohide(False)
        self.tooltipdata.setMainText(self.data["title"])
        self.tooltipdata.setSubText(i18n("Click to see on Last.fm"))
        self.tooltipdata.setImage(icon)
        Plasma.ToolTipManager.self().setContent(self.lb_image_small, self.tooltipdata)
        Plasma.ToolTipManager.self().registerWidget(self.lb_image_small)

    @QtCore.pyqtSlot(name="set_map")
    def set_map(self):
        #print "set_map for '%s'" % self.data["title"]
        # setToolTip on address label.
        mapimg = self.icongetter.get_icon_path("map")
        #print "Map path: " + str(mapimg)
        if mapimg:
            self.lb_address.nativeWidget().setToolTip("<img src=\"%s\" />" % mapimg)
        else:
            print "Invalid map path: " + str(mapimg)

    def setHeadline(self, headline):
        #self.headline.nativeWidget().setWordWrap(False)
        self.lb_headline.setText("<a href=\"%s\">%s</a>" % (self.data["url"], headline))
        f = self.lb_headline.nativeWidget().font()
        f.setBold(True)
        self.lb_headline.nativeWidget().setFont(f)

    def setStartDate(self, startdate):
        self.lb_startdate.nativeWidget().setWordWrap(False)
        self.lb_startdate.setText(startdate)

    def setDesc(self, desc):
        #print "setDesc"
        # Setup tool tip
        self.tooltipdata = Plasma.ToolTipContent()
        self.tooltipdata.setAutohide(False)
        self.tooltipdata.setClickable(True)
        self.tooltipdata.setMainText(self.data["title"])
        if len(desc) > 0:
            self.tooltipdata.setSubText(desc)
        #self.tooltipdata.setImage(icon)
        Plasma.ToolTipManager.self().setContent(self.lb_headline, self.tooltipdata)
        #Plasma.ToolTipManager.self().registerWidget(self.lb_image_small)

        #self.lb_headline.nativeWidget().setToolTip(desc)

    def google_maps_url(self):
        query = "%s,%s %s,%s" % (self.data["street"], self.data["postalcode"], self.data["city"], self.data["country"])
        query = query.replace(" ", "+")
        #query=urlencode((('v',1.0), ('ie', 'UTF8'), ('q',query.encode('utf-8'))))
        #query = quote(query.encode('utf-8'))
        return "http://maps.google.com/?q=" + query

    def setAddress(self, street, postalcode, city, country):
        # TODO: Check which address parts are available and format
        #       address and query from that.
        #       Don't link if not enough parts.
        address = "%s, %s %s, %s" % (street, postalcode, city, country)
        query = "%s,%s %s,%s" % (street, postalcode, city, country)
        query = quote(query.encode('utf-8'))
        self.lb_address.setText("<a href=\"http://maps.google.com/?q=%s\">%s</a>" % (query, address))

    def setGeoLocation(self, geolocation):
        # TODO: Lookup geolocation code in websvn (Maybe drop this method
        #       altogether as it is not needed).
        #self.geolocation.setText(data.geolocation)
        pass

    def setWebsite(self, website):
        pass

    def setLastUrl(self, lasturl):
        pass

    def setTicketsUrl(self, ticketsurl):
        pass

    def setTags(self, tags):
        txt = ", ".join(tags)
        self.lb_tags.setText(txt)

    def startDate(self):
        #try:
        return datetime.datetime.strptime(self.data["startDate"], "%a, %d %b %Y %H:%M:%S")
        #except: # if we're not initialized yet return current time
        #    return datetime.datetime.now()

    def open_event(self):
        # Open browser with last.fm event
        #print "LastFMEvent::openEvent"
        self.open_url.emit(QString(self.data["url"]))

    def open_venue(self):
        # Open browser with last.fm venue
        #print "LastFMEvent::open_venue"
        self.open_url.emit(QString(self.data["venue"]["url"]))

    def open_map(self):
        # Open browser with Google Maps
        #print "LastFMEvent::open_map"
        self.open_url.emit(self.google_maps_url())

    def open_mailer(self):
        # Send event link by mail
        #print "LastFMEvent::open_mailer"
        url = "mailto:?subject=%s&body=%s" % (self.data["title"], self.data["url"])
        self.open_url.emit(QString(url))

    def share_event(self, action):
        print action.iconText()
        name = str(action.data().toString())
        print name
        sid = socialnetworks[name]["id"]
        ws = webservices["shareaholic"]
        #key = ws["key"]
        url = ws["url"] % (sid, self.data["title"], self.data["url"])
        print url
        self.open_url.emit(QString(url))

    def bt_share_clicked(self):
        scene = self.bt_share.scene()
        if scene:
            #print "scene: " + str(scene)
            pos = scene.popupPosition(self.bt_share, self.share_menu.sizeHint())
            #print "pos: %ix%i" % (pos.x(), pos.y())
            self.share_menu.popup(pos)
